package com.faker.service;

import com.faker.core.dto.GenerationRequest;
import com.faker.core.generate.common.SqlGenerate;
import com.faker.core.generate.data.DataGenerator;
import com.faker.dao.DataGenerateDao;
import com.faker.entity.SysConnection;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
@Slf4j
public class DataGenerateService {
    @Resource
    DataGenerateDao dataGenerateDao;


    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public List<Map<String, Object>> getGlobalParams(GenerationRequest generationRequest) {
        //获取要生成的记录数量
        Integer generationNum = generationRequest.getGenerationNum();
        //获取全局变量表格
        List<Map<String, Object>> globalTableData = generationRequest.getGlobalTableData();
        //预先生成全局变量放到List<Map<String, Object>>中，生成第n条记录则用globalParams中的第n条，从而使得外键关联
        List<Map<String, Object>> globalParams = globalParamsGeneration(generationNum, globalTableData);

        return globalParams;
    }


    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public int startGeneration(GenerationRequest generationRequest, List<Map<String, Object>> globalParams) {
        //获取表结构列表
        List<List<Map<String, Object>>> tableDataList = generationRequest.getTableDataList();
        int completedNum = 0;
        //轮询表结构列表生成数据
        for (List<Map<String, Object>> tableData : tableDataList) {
            //SQL语句生成
            String insertSql = SqlGenerate.insertSqlStringGen(tableData, globalParams.size());
            System.out.println(insertSql);
            //SQL参数生成多条
            ArrayList<Object> params = paramsGeneration(globalParams, tableData, globalParams.size());

            //执行数据入库
            int num = dataGenerateDao.startGeneration(insertSql, params);
            log.info("表：" + tableData.get(0).get("tableName").toString() + ",生成数量：" + num);
            completedNum += num;
        }

        return completedNum;

    }

    /**
     * 生成全局变量
     *
     * @param globalTableData
     * @return
     */
    private List<Map<String, Object>> globalParamsGeneration(Integer generationNum, List<Map<String, Object>> globalTableData) {
        //存放生成的generationNum条全局变量数据
        List<Map<String, Object>> resultList = new ArrayList<>();

        //获取出全局变量配置表格中的自定义表的行数据
        List<Map<String, Object>> globalTableDataFilterOfTable = getGlobalTableDataFilterOfTable(globalTableData);


        //预先查询自定表中的数据，获取数量为generationNum条，存入tableGenCacheMap缓存Map中
        HashMap<String, Object> tableGenCacheMap = getTableGenCacheMap(generationNum, globalTableDataFilterOfTable);
        //获取的数据库表记录数最少的记录数
        Integer tableDataListSizeMin = (Integer) tableGenCacheMap.get("tableDataListSizeMin");

        //获取数量为tableDataListSizeMin条（短板法则），存入globalTableParamsListOfTableGen
        List<Map<String, Object>> globalTableParamsListOfTableGen = new ArrayList();
        for (Integer i = 0; i < tableDataListSizeMin; i++) {
            //存放一个全局变量配置表格的数据
            HashMap<String, Object> globalTableParamsMapOfTableGen = new HashMap<>();
            for (Map<String, Object> globalTableRow : globalTableDataFilterOfTable) {
                Object globalKeyObj = globalTableRow.get("globalKey");
                Object genTypeObj = globalTableRow.get("genType");
                Object genKeyCode = globalTableRow.get("genKeyCode");
                Object genKeyTable = globalTableRow.get("genKeyTable");
                String[] split = genKeyTable.toString().split("\\.");
                String tableName = split[0];
                String fieldName = split[1];
                List<Map<String, Object>> tableDataList = (List<Map<String, Object>>) tableGenCacheMap.get(tableName);
                Map<String, Object> tableData = tableDataList.get(i);

                globalTableParamsMapOfTableGen.put(globalKeyObj.toString(), tableData.get(fieldName));
            }
            //将每一个全局变量配置表格的数据汇总到globalTableParamsListOfTableGen
            globalTableParamsListOfTableGen.add(globalTableParamsMapOfTableGen);
        }


        //tableDataListSizeMin默认等于generationNum，如果查询的数据库表中的数据tableDataListSizeMin小于generationNum则取最小值
        for (Integer i = 0; i < tableDataListSizeMin; i++) {
            //存放globalTable的全局变量
            HashMap<String, Object> globalTableParams = new HashMap<>();

            for (Map<String, Object> globalTableRow : globalTableData) {
                Object globalKeyObj = globalTableRow.get("globalKey");
                Object genTypeObj = globalTableRow.get("genType");
                Object genKeyCode = globalTableRow.get("genKeyCode");
                Object genKeyTable = globalTableRow.get("genKeyTable");
                if (genTypeObj != null && (genKeyCode != null || genKeyTable != null)) {
                    String genTypeString = genTypeObj.toString();
                    //生成全局主键数据
                    if (genTypeString.equals("primary")) {
                        String genKey = (String) genKeyCode;
                        //获取全局主键数据
                        Object param = DataGenerator.dataGeneratorForGlobalIncrease(genKey);
                        //将数据放到globalTableMap中
                        globalTableParams.put(globalKeyObj.toString(), param);
                    }

                    //生成全局自定义表数据
                    if (genTypeString.equals("table")) {
                        //将数据放到globalTableMap中
                        globalTableParams.put(globalKeyObj.toString(), globalTableParamsListOfTableGen.get(i).get(globalKeyObj.toString()));
                    }
                }
            }
            resultList.add(globalTableParams);
        }
        return resultList;
    }

    /**
     * 获取全局变量生成需要的表数据
     *
     * @param generationNum
     * @param globalTableDataFilterOfTable
     * @return
     */
    private HashMap<String, Object> getTableGenCacheMap(Integer generationNum, List<Map<String, Object>> globalTableDataFilterOfTable) {
        //记录数据库表记录数最小的数据表，tableDataListSizeMin，后续使用tableDataListSizeMin替代generationNum
        Integer tableDataListSizeMin = generationNum;
        //查询需要的数据库中的数据并返回，目的是后续同一个全局表中的数据如果出自一个数据库表的不同字段，则保证为同一行数据
        HashMap<String, Object> tableGenCacheMap = new HashMap<>();
        for (Map<String, Object> globalTableRow : globalTableDataFilterOfTable) {
            Object globalKeyObj = globalTableRow.get("globalKey");
            Object genTypeObj = globalTableRow.get("genType");
            Object genKeyCode = globalTableRow.get("genKeyCode");
            Object genKeyTable = globalTableRow.get("genKeyTable");

            String[] split = genKeyTable.toString().split("\\.");
            String tableName = split[0];
            String fieldName = split[1];

            //根据tableName查询数据库表
            List<Map<String, Object>> tableDataList = dataGenerateDao.getTableDataList(tableName, generationNum);
            //获取tableDataList.size()
            if (tableDataListSizeMin > tableDataList.size()) {
                tableDataListSizeMin = tableDataList.size();
            }
            //将表中的数据读到变量内存中
            tableGenCacheMap.put(tableName, tableDataList);
        }

        tableGenCacheMap.put("tableDataListSizeMin", tableDataListSizeMin);
        return tableGenCacheMap;
    }


    /**
     * 获取出全局变量配置表格中的自定义表的行数据
     *
     * @param globalTableData
     * @return
     */
    private static List<Map<String, Object>> getGlobalTableDataFilterOfTable(List<Map<String, Object>> globalTableData) {
        //对globalTableData的数据进行轮询过滤，获取出自定义表生成数据的行数据，存入globalTableDataFilterOfTable
        List<Map<String, Object>> globalTableDataFilterOfTable = new ArrayList<>();
        for (Map<String, Object> globalTableRow : globalTableData) {
            Object globalKeyObj = globalTableRow.get("globalKey");
            Object genTypeObj = globalTableRow.get("genType");
            Object genKeyCode = globalTableRow.get("genKeyCode");
            Object genKeyTable = globalTableRow.get("genKeyTable");
            if (genTypeObj != null && genKeyTable != null) {
                String genTypeString = genTypeObj.toString();
                if (genTypeString.equals("table")) {
                    globalTableDataFilterOfTable.add(globalTableRow);
                }
            }
        }
        return globalTableDataFilterOfTable;
    }


    /**
     * 生成需要入库的伪数据
     *
     * @param globalParams
     * @param tableData
     * @param generationNum
     * @return
     */
    public ArrayList<Object> paramsGeneration(List<Map<String, Object>> globalParams, List<Map<String, Object>> tableData, Integer generationNum) {

        ArrayList<Object> params = new ArrayList<>();

        for (Integer n = 0; n < generationNum; n++) {
            for (Map<String, Object> table : tableData) {
                Object tableNameObj = table.get("tableName");
                Object genTypeObj = table.get("genType");

                Object genKeyGlobal = table.get("genKeyGlobal");
                Object genKeyCode = table.get("genKeyCode");
                Object genKeyTable = table.get("genKeyTable");

                if (genTypeObj != null && (genKeyCode != null || genKeyTable != null || genKeyGlobal != null)) {
                    String genTypeString = genTypeObj.toString();
                    //通过全局变量
                    if (genTypeString.equals("global")) {
                        //从globalParams列表中获取预先生成的全局变量
                        Object param = globalParams.get(n).get(genKeyGlobal.toString());
                        params.add(param);
                    }

                    //通过代码生成
                    if (genTypeString.equals("code")) {
                        ArrayList<String> genKeyList = (ArrayList<String>) genKeyCode;
                        Object param = DataGenerator.dataGeneratorByCode(genKeyList, tableNameObj);
                        params.add(param);
                    }

                    //通过查表生成
                    if (genTypeString.equals("table")) {
                        String genKeyString = genKeyTable.toString();
                        //通过genKey生成查询语句：表名.字段名
                        String[] split = genKeyString.split("\\.");
                        String tableName = split[0];
                        String fieldName = split[1];
                        ArrayList<Object> fieldList = new ArrayList<>();
                        fieldList.add(fieldName);
                        String selectParamsSql = SqlGenerate.selectSqlStringGen(tableName, fieldList);

                        params.add("");
                    }
                }
            }
        }
        return params;
    }


}
